﻿using Audio.Diagnostics;
using AudioVisualizer;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Media.Audio;
using Windows.Media.Render;

namespace Audio
{
    internal class AudioVisualizationImpl : IAudioVisualization
    {
        private AudioGraph audioGraph;
        private AudioDeviceInputNode audioDeviceInputNode;
        private PlaybackSource playbackSource;
        private IVisualizationSource visualizationSource;
        public bool IsInited { get; private set; } = false;

        public bool IsDisposed { get; private set; } = false;


        public VisualizationDataFrame GetData()
        {
            //Debug.WriteLine("GetData");
            if (IsInited && !IsDisposed && visualizationSource != null)
            {
                var data = visualizationSource.GetData();
                //Debug.WriteLine("GetData end");
                return data;
            }
            //Debug.WriteLine("GetData end with null");
            return null;
        }
        private object locker = new object();


        public void Dispose()
        {
            Debug.WriteLine("lock wait:Audio.AudioVisualizationImpl1.Dispose");
            try
            {
                lock (locker)
                {
                    Debug.WriteLine("lock enter:Audio.AudioVisualizationImpl1.Dispose");
                    Debug.WriteLine("Audio.AudioVisualizationImpl1 Dispose Begin");
                    if (IsDisposed || !IsInited)
                    {
                        Debug.WriteLine("Audio.AudioVisualizationImpl1 Dispose Already");
                        return;
                    }
                    audioGraph?.Stop();
                    if (playbackSource != null)
                    {
                        playbackSource.SourceChanged -= PlaybackSource_SourceChanged;
                        visualizationSource = null;
                        playbackSource = null;
                    }
                    if (audioDeviceInputNode != null)
                    {
                        audioDeviceInputNode.Dispose();
                        audioDeviceInputNode = null;
                    }
                    if (audioGraph != null)
                    {
                        audioGraph.Dispose();
                        audioGraph = null;
                    }
                    Debug.WriteLine("Audio.AudioVisualizationImpl1 Dispose End");
                    IsDisposed = true;
                }
                
            }
            catch (Exception)
            {
                Debug.WriteLine("AudioVisualization crash: in Disposal ");
            }
        }




        public void Init()
        {
            Debug.WriteLine("lock wait:Audio.AudioVisualizationImpl1.init");
            try
            {
                lock (locker)
                {
                    Debug.WriteLine("lock enter:Audio.AudioVisualizationImpl1.init");
                    Debug.WriteLine("Audio.AudioVisualizationImpl1 Init Begin");
                    
                    if (IsDisposed || IsInited)
                    {
                        Debug.WriteLine("Audio.AudioVisualizationImpl1 Init Already");
                        return;
                    }
                    var waiter = HP.UtilsLib.TaskAwaiterHelper.GetTaskAwaiter(
                        async () =>
                        {
                            return await AudioGraph.CreateAsync(
                                new AudioGraphSettings(AudioRenderCategory.Speech)
                                );
                        }
                        );
                    var result = waiter.GetResult();
                    waiter.Dispose();
                    if (result.Status != AudioGraphCreationStatus.Success)
                    {
                        Debug.WriteLine($"Audio.AudioVisualizationImpl1 Create AudioGraph Fail,status={result.Status}");
                        return;
                    }
                    Debug.WriteLine($"Audio.AudioVisualizationImpl1 Create AudioGraph Success");
                    audioGraph = result.Graph;
                    var waiter2 = HP.UtilsLib.TaskAwaiterHelper.GetTaskAwaiter(
                        async () =>
                        {
                            return await audioGraph.CreateDeviceInputNodeAsync(Windows.Media.Capture.MediaCategory.Speech);
                        }
                        );
                    var result2=waiter2.GetResult();
                    waiter2.Dispose();
                    if (result2.Status != AudioDeviceNodeCreationStatus.Success)
                    {
                        Debug.WriteLine($"Audio.AudioVisualizationImpl1 Create DeviceInputNode Fail,status={result2.Status}");
                        return;
                    }
                    Debug.WriteLine($"Audio.AudioVisualizationImpl1 Create DeviceInputNode Success");
                    audioDeviceInputNode = result2.DeviceInputNode;
                    playbackSource = PlaybackSource.CreateFromAudioNode(audioDeviceInputNode);
                    Debug.WriteLine($"Audio.AudioVisualizationImpl1 Create PlaybackSource Success");
                    if (playbackSource == null)
                    {
                        Debug.WriteLine($"Audio.AudioVisualizationImpl1 Create PlaybackSource Fail");
                        return;
                    }
                    visualizationSource = playbackSource.Source;
                    playbackSource.SourceChanged += PlaybackSource_SourceChanged;
                    audioGraph?.Start();
                    IsInited = true;
                    Debug.WriteLine("Audio.AudioVisualizationImpl1 Init End");
                }
            }
            catch (Exception)
            {
                Debug.WriteLine("AudioVisualization crash: in Init");
            }
            

        }

        private void PlaybackSource_SourceChanged(object sender, IVisualizationSource args)
        {
            visualizationSource = args;
        }
    }
}
